using System;
using System.Collections;

namespace Tycho.Parser.Peg {
    public class SequenceRule : Rule {
        public IRule[] Rules;
        private IInfixInformation _infixInformation;

        public SequenceRule (params IRule[] rules) {
            Rules = rules;
        }

        public override bool IsInfix {
            get {
                if (Rules.Length > 1) {
                    return Rules[0] is NamedRule && Rules[Rules.Length - 1] is NamedRule;
                }

                return false;
            }
        }

        public void SetInfixInformation (IInfixInformation infixInformation) {
            _infixInformation = infixInformation;
        }

        public override IInfixInformation InfixInformation
        {
            get
            {
                return _infixInformation;
            }
        }

        public override Yield Parse (char[] source, int index, ParseContext context, string sourceString, ParseEnvironment environment, Func<RuleParseResult, Yield> continuation) {
            return ParseNextRule (Rules.GetEnumerator (), null, source, index, context, sourceString, environment, continuation);
        }

        private Yield ParseNextRule (IEnumerator rulesEnumerator, RuleParseResult lastResult, char[] source, int index, ParseContext context, string sourceString, ParseEnvironment environment, Func<RuleParseResult, Yield> continuation) {
            if (rulesEnumerator.MoveNext ()) {
                var rule = (IRule) rulesEnumerator.Current;

                return rule.Parse (source, index, context, sourceString, environment, result => {
                    if (result == null) {
                        return () => continuation (null);
                    }

                    if (lastResult != null) {
                        result.MergeCapturesFrom (lastResult);
                    }

                    return () => ParseNextRule (rulesEnumerator, result, source, result.Index, result.Context, sourceString, environment, continuation);
                });
            } else {
                return () => continuation (lastResult);
            }
        }
    }
}